#ifndef SOS_PROCESS_H
#define SOS_PROCESS_H

#include <clock/clock.h>
#include <cspace/cspace.h>
#include <sel4/sel4.h>

#include "list.h"
#include "vm/pt_list.h" // XXX replace with generic list
#include "vfs.h"

#define SOS_PROCESS_SUCCESS  (0)
#define SOS_PROCESS_OOM      (1)
#define SOS_PROCESS_MAXPROC  (2)
#define SOS_PROCESS_NOENT    (3)
#define SOS_PROCESS_INVAL    (4)

/* seL4 priority for all running SOS processes */
#define SOS_PROCESS_PRIORITY (0)

#define SOS_PID_MIN (2)
// #define SOS_PID_MAX (35)
#define SOS_PID_MAX (65536)

/* Forward declarations of page table and region types */
typedef struct page_table_entry page_table_entry;
typedef page_table_entry *sos_page_table;
typedef sos_page_table *sos_page_directory;
typedef struct sos_region sos_region;
typedef sos_region **sos_region_list;

/* SOS PCB for a single process */
typedef struct sos_pcb {
    seL4_Word pid;                  /* Unique identifier */

    int running;                    /* Proc has been schedulable at least once */
    timestamp_t stime;              /* Time process was created, in usecs */
    char app_name[SOS_PATH_MAX];    /* Name of application */

    cspace_t *cspace;               /* seL4 croot */
    seL4_Word ipc_vaddr;            /* SOS vaddr for IPC buffer */
    seL4_CPtr ipc_cap;              /* seL4 cap for IPC buffer */
    seL4_TCB tcb_cap;               /* Cap for seL4 TCB */
    seL4_Word tcb_addr;             /* vaddr for seL4 TCB */
    seL4_CPtr ep_cap;               /* Fault endpoint */

    /* SOS VM subsystem */ // XXX Could be a single structure
    sos_page_directory sos_pd;      /* Shadow page directory */
    sos_region *regions;            /* List of VM regions */
    seL4_ARM_PageDirectory seL4_pd; /* seL4 page directory cap (vroot) */
    seL4_Word seL4_pd_addr;         /* seL4 page directory sos_vaddr */
    sos_pt_list *pt_caps;           /* Linked list of seL4 page table caps */

    /* SOS VFS subsystem */
    sos_fd *fd_table;               /* Hash table of process FDs */

    /* Store all child PIDs (until that PID is reused) */
    list children;

    /* Store the PCBs of any process_waiting procs as a linked list */
    sos_pcb *waiter;
    sos_pcb *next;

    /* If the process is sleeping, the timer ID goes here */
    seL4_Word sleep_timer;
    /* Lazy place to store the reply cap during a syscall */
    seL4_Word reply_cap;

    /* If the process is deleted while mid-syscall, mark here and clean up */
    int abort;

    /* Use the PCB structs as a hash table via uthash */
    UT_hash_handle hh;
} sos_pcb;

/* Various callback types to be passed into process_ functions */
typedef void (*process_create_cb)(int err, int pid, void *cookie);
typedef void (*process_delete_cb)(int err, void *cookie);
typedef void (*process_wait_cb)(int err, void *cookie);

int process_create(char *app_name, process_create_cb cb, void *cookie);

int process_delete(sos_pcb *pcb, process_delete_cb cb, void *cookie);

int process_wait(sos_pcb *pcb, int target_pid);

int process_status(sos_pcb *pcb, int proc_num);

int process_register_child(sos_pcb *parent, sos_pcb *child, int newpid);

int lookup_pcb(int pid, sos_pcb **pcb);

#endif // SOS_PROCESS_H
